/**
* HTMLSelect - a peer component for the HTML Select form component
*
* Copyright (c) 2002
* Marty Phelan, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.taursys.html;
import com.taursys.html.render.HTMLSelectFieldRenderer;
import com.taursys.model.ObjectArrayValueHolder;
/**
* <p>This components is a peer component for the <Select> tag in an HTML
* form. This component is a specialization of the <code>SelectField</code>.
* Like the <code>SelectField</code>, this component (using a
* <code>DefaultSelectModel</code>), can display a selection from a
* list of objects. It can also change the selection from user input.</p>
*
* <p>The selection is made and displayed using the property indicated by
* the <code>displayPropertyName</code>. The <code>displayPropertyName</code>
* is effectively the "selection key". If the <code>displayPropertyName</code>
* is null or blank, then the <code>toString</code> method is used instead.
* For example, given a list of Address objects, and a
* <code>displayPropertyName</code> of "zipCode", the display value for
* "Juneau, AK 99801 USA" would be "99801". To change the selection, you would
* supply a different zipCode from the list.</p>
*
* <p>The HTMLSelect uses a specialized renderer which will create a list
* of html <Option> tags with the displayPropertyName value for each
* item in the list. Using the same example as above, after rendering the
* document would contain:</p>
*
* <pre>
* <select name="zip" id="zip">
* <option>99801</option>
* <option>99824</option>
* <option>99827</option>
* </select>
* </pre>
*
* <p>This component can function in three different ways, depending on the
* properties you set:</p>
*
* <ul>
* <li>input only - set the <code>parameter</code> property.</li>
* <li>output only - set the <code>id</code> property.</li>
* <li>input and output - set both the <code>parameter</code> and
* <code>id</code> properties.</li>
* </ul>
*
* <p>When used for output, the value is rendered in the XML document as a
* text node by default. If you want the value to be rendered to
* an attribute of the node instead, you must change the <code>renderer</code>
* to an <code>AttributeTextFieldRenderer</code> and the the <code>attribute</code>
* property to the name of the attribute.</p>
*
* <p>When used for input, this component receives its value from the
* <code>InputDispatcher</code> AFTER the <code>openForm</code> method of the
* <code>ServletForm</code> by default. If you want this component to receive
* its input earlier (at the same time as <code>Parameters</code>), set the
* <code>earlyInputNotify</code> property to <code>true</code>.</p>
*
* <p>By default, this component uses a <code>DefaultSelectModel</code>.
* You can change this by overriding the <code>createDefaultModel</code> method
* or explicitly setting the <code>model</code> property.</p>
*
* <b>Setting the List</b>
* <p>
* The <code>list</code> must be a type of <code>CollectionValueHolder</code>
* (example: <code>VOCollectionValueHolder</code> or
* <code>VOListValueHolder</code>).
* The holder can contain any type of object (but they must all be instances
* of the same class).
* <p>
* If the <code>list</code> is an <code>ObjectArrayValueHolder</code>, then the
* <code>toString()</code> method is used as the display value (regardless of
* the <code>displayPropertyName</code>). If used in the bound mode, the whole
* object itself is stored in the target ValueHolder's object (regardless of
* the property names listed in the <code>setListPropertyNames</code> method).
* It is important to make sure that the <code>valueHolder</code> property
* is the same type as the objects in the <code>ObjectArrayValueHolder</code>
* or a <code>ModelException</code> will occur.
* <p>
* You can also preset the <code>list</code> in the constructor by passing it an
* array of Objects to be used for the <code>list</code>. The resulting
* <code>list</code> will be an <code>ObjectArrayValueHolder</code>.
* <p>
* The following is an example of this usage:</p>
*
* <pre>
* SelectField color = new SelectField(new String[] {
* "Red", "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet",
* });
* ...
* private void jbInit() throws Exception {
* ...
* color.setParameter("color");
* color.setId("color");
* ...
* this.add(color);
* }
* </pre>
*
* <p>This component can be used in a variety of ways. It can be used in an
* un-bound mode, where the current selection is maintained internally. It can
* also be used in a bound mode where the current selection is propagated to a
* value holder. When used in the bound mode, either a single property, or
* multiple properties can be set in the value holder. The following sections
* describe the required settings to make for each of the modes.</p>
*
* <b>Un-bound Mode (uses internal VariantValueHolder)</b>
* <p>
* When used in this mode this component uses an internal
* <code>VariantValueHolder</code> to hold the current selection. By default a
* <code>VariantValueHolder</code> is created with a data type of
* <code>String</code>. To set a different data type use the constructor which
* takes a data type as a parameter. (example
* <code>new SelectField(DataTypes.TYPE_INT)</code>).
* <p>
* To use this component in the un-bound mode, you must set the following
* properties:
* <ul>
* <li><code>list</code> - should be set to a type of
* <code>CollectionHolder</code> which holds the list of options
* (see "Setting the List").
* </li>
* <li><code>displayPropertyName</code> - the name of the property to display
* (property of objects in list). Example: given a list of "Location" objects
* with a property called "locationName", use
* <code>setDisplayPropertyName("locationName")</code>
* to display the zipCode. IMPORTANT - The displayed property choosen must
* result in a unique list of values, otherwise the intended value may not be
* selected/displayed.
* </li>
* <li><code>listPropertyNames</code> - set a single source property name in the
* <code>list</code> objects. Example: Given a list containing "Location"
* objects which has properties "zipCode", "cityName", "stateAbbr", and
* "country", to make the zipcode the internal value use
* <code>setListPropertyNames(new String[] {"zipCode"})</code>.
* <p>
* If the <code>list</code> is an <code>ObjectArrayValueHolder</code>, then
* the property name should always be a single "value" (which is the default).
* </li>
* <li><code>propertyName</code> - must be "value" (which is the default).
* </li>
* <li><code>nullDisplay</code> - String to display in list for null selection.
* Example: "--- Nothing Selected ---"
* </li>
* </ul>
* <b>Bound Mode</b>
* <p>
* To use this component in the bound mode, use the same properties as
* described in the Un-bound Mode, plus the following additional properties:
* <ul>
* <li><code>valueHolder</code> - should be set to the target
* <code>ValueHolder</code> which contains the current selection and will be
* updated if the selection is changed.
* </li>
* <li><code>propertyName</code> - set this to the first (or only)
* <code>ValueHolder</code> object property name which will be bound to the
* selection. Example: given a <code>ValueHolder</code> with an
* "Address" object which has a "zipCode" property, use
* <code>setPropertyName("zipCode")</code> to store the current selection in
* the "Address.zipCode" property.
* </li>
* <li><code>propertyNames</code> - use this when you want to set more than
* 1 property in the <code>ValueHolder</code> object. Example: assume you want
* to set not only the "zipCode" property, but also the "city", "state" and
* "country" properties, use
* <code>setPropertyNames(new String[] {"zipCode","city","state","country"})</code>
* </li>
* <li><code>listPropertyNames</code> - set the to the source property name(s)
* in the <code>list</code> objects. IMPORTANT - The name(s) of the
* <code>listPropertyNames</code> properties MUST be
* in the same ORDER as the <code>propertyName(s)</code>. The names in the
* <code>listPropertNames</code> may be different than the names in the
* <code>propertyNames</code> since they are associated
* with in objects in the <code>list</code>, not the <code>valueHolder</code>.
* Example: Given a <code>list</code>
* containing "Location" objects which has properties "zipCode", "cityName",
* "stateAbbr", and "country", for a single property use
* <code>setListPropertyNames(new String[] {"zipCode"})</code>. For
* multiple properties use
* <code>setListPropertyNames(new String[] {"zipCode", "cityName", "stateAbbr",
* "country"})</code>
* <p>
* If the <code>list</code> is an <code>ObjectArrayValueHolder</code>, then
* the property name should always be a single "value" (which is the default).
* </li>
* </ul>
*
* <b>Other Important Information</b>
* <p>
* When a selection is made, the values are copied from the properties in the
* <code>list</code> to the properties in the <code>valueHolder</code> object.
* The property names in <code>propertyNames[]</code> and
* <code>listPropertyNames[]</code> must appear in a corresponding order.
* <p>
* A "null" item will always be added to the <code>displayOptionList</code>.
* When the "null" item is selected, a null will be assigned to the
* <code>propertyNames[]</code> in the <code>valueHolder</code> object.
* The actual "null" item to to display is defined by the
* <code>nullDisplay</code> (default is "--none--").
* <p>
* The <code>format</code> and <code>formatPattern</code> govern the display
* property in this component. The <code>getText</code> method returns the
* formatted display property, while the <code>setText</code>
* method changes the current selection to one whose display matches the given
* value. If you attempt to <code>setText</code> for an item that is not in
* the list, a <code>NotInListException</code> will be thrown.
*/
public class HTMLSelect extends com.taursys.xml.SelectField {
/**
* Constructs a new HTMLSelect component.
*/
public HTMLSelect() {
setRenderer(new HTMLSelectFieldRenderer(this));
}
/**
* Creates a new HTMLSelect of the given data type.
* @param javaDataType the data type for the VariantValueHolder
* @see com.taursys.util.DataTypes for defined data type constants TYPE_XXXXXX.
*/
public HTMLSelect(int javaDataType) {
super(javaDataType);
setRenderer(new HTMLSelectFieldRenderer(this));
}
/**
* Constructs a new HTMLSelect with the given list of options.
*/
public HTMLSelect(Object[] array) {
setRenderer(new HTMLSelectFieldRenderer(this));
setList(new ObjectArrayValueHolder(array));
}
/**
* Constructs a new HTMLSelect of the given data type with the given list of
* options.
* @param javaDataType the data type for the VariantValueHolder
* @param array the array of options
* @see com.taursys.util.DataTypes for defined data type constants TYPE_XXXXXX.
*/
public HTMLSelect(int javaDataType, Object[] array) {
super(javaDataType);
setRenderer(new HTMLSelectFieldRenderer(this));
setList(new ObjectArrayValueHolder(array));
}
}